/* 
 * AUTHOR: Kevin Lam
 */

package com.apps.datastore;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.apps.datastore.dao.BookInformationObject;
import com.apps.datastore.dao.CourseInformationObject;
import com.apps.datastore.dao.DepartmentInformationObject;
import com.apps.datastore.dao.SectionInformationObject;
import com.apps.datastore.dao.UniqueCourseObject;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.SortDirection;
import com.google.appengine.api.datastore.Transaction;
import com.google.appengine.api.datastore.Query.FilterOperator;

public class UBCCourseSpiderDatastore {

	// Name and key of this set

	public static final String DATASTORE_ENTITY_SET_NAME = "UBC Course Data Set";
	public static final String DATASTORE_ENTITY_KEY_NAME = "UBC_COURSE_DATA";

	// Department Entity

	public static final String DEPARTMENT_KIND = "Departments";

	// Department entity's property names

	public static final String DEPARTMENT_ID_PROPERTY = "Subject Code";
	public static final String SUBJECT_TITLE_PROPERTY = "Subject Title";
	public static final String FACULTY_PROPERTY = "Faculty";

	// Course Entity

	private static final String COURSE_KIND = "Courses";

	// Course entity's property names

	public static final String COURSE_ID_PROPERTY = "Course ID";
	public static final String COURSE_TITLE_PROPERTY = "Course Title";
	public static final String PREREQ_PROPERTY = "Pre-requisites";
	public static final String COREQ_PROPERTY = "Co-requisites";
	public static final String CREDIT_PROPERTY = "Credits";

	// Section Entity

	private static final String SECTION_KIND = "Section";

	// Section entity's property names

	public static final String SECTION_ID_PROPERTY = "Section ID";
	public static final String ACTIVITY_PROPERTY = "Activity";
	public static final String TERM_PROPERTY = "Term";
	public static final String DAY_PROPERTY = "Day";
	public static final String LOCATION_PROPERTY = "Location";
	public static final String START_PROPERTY = "Start";
	public static final String END_PROPERTY = "End";
	public static final String INSTRUCTOR_PROPERTY = "Instructor";
	public static final String BUILDING_PROPERTY = "Building";
	public static final String ROOM_PROPERTY = "Room";
	public static final String CDF_PROPERTY = "Credit/D/Fail";
	public static final String DROP_NO_W_PROPERTY = "Drop No W Date";
	public static final String DROP_W_PROPERTY = "Drop W Date";

	// Books Entity

	public static final String BOOK_KIND = "Books";

	// Books entity's property names

	public static final String BOOK_TITLE_PROPERTY = "Book Title";
	public static final String BOOK_REQUIRED_PROPERTY = "Book Requirement";
	public static final String BOOK_AUTHOR_PROPERTY = "Book Author";
	public static final String BOOK_ISBN_PROPERTY = "Book ISBN";

	private DatastoreService datastore;

	public UBCCourseSpiderDatastore() {
		datastore = DatastoreServiceFactory.getDatastoreService();
	}

	public void initSchema() { // Initiate the first entity for our set (the
								// highest parent node)
		Transaction txn = datastore.beginTransaction();
		Entity e = new Entity(DATASTORE_ENTITY_SET_NAME,
				DATASTORE_ENTITY_KEY_NAME);
		datastore.put(e);
		txn.commit();
	}

	public void traceSchema() {
		Query q = new Query();
		Key k = KeyFactory.createKey(DATASTORE_ENTITY_SET_NAME,
				DATASTORE_ENTITY_KEY_NAME);
		q.setAncestor(k);
		q.setKeysOnly();
		List<Entity> l = datastore.prepare(q).asList(
				FetchOptions.Builder.withDefaults());
		for (Iterator i = l.iterator(); i.hasNext();) {
			Entity e = (Entity) i.next();
			System.out.println(e.getKey().toString());
		}
	}

	public void dropSchema() {
		Query q = new Query();
		Key k = KeyFactory.createKey(DATASTORE_ENTITY_SET_NAME,
				DATASTORE_ENTITY_KEY_NAME);
		q.setAncestor(k);
		q.setKeysOnly();
		List<Entity> l = datastore.prepare(q).asList(
				FetchOptions.Builder.withDefaults());
		for (Iterator i = l.iterator(); i.hasNext();) {
			Entity e = (Entity) i.next();
			System.out.println("deleting " + e.getKey());
			datastore.delete(e.getKey());
		}
	}

	/**
	 * Attempts to add a department entity to the datastore, will fail if
	 * duplicate was found in datastore
	 * 
	 * @param dio
	 *            DepartmentInformationObject - department data to be added
	 * @return boolean value whether add was successful or not
	 */
	public boolean addDepartment(DepartmentInformationObject dio) { // Add a
																	// department
																	// to
																	// datastore
																	// using a
																	// department
																	// information
																	// object
																	// dao
		if (!checkDepartmentExists(dio)) { // Checks if department exists first
			Key k = KeyFactory.createKey(DATASTORE_ENTITY_SET_NAME,
					DATASTORE_ENTITY_KEY_NAME); // Get the key of the parent
												// node you wish to attach
												// entity to (in this case our
												// top most node)
			Transaction txn = datastore.beginTransaction(); // begin a
															// transaction for
															// atomic adding
			Entity e = new Entity(DEPARTMENT_KIND, k); // Create the entity with
														// the parent designated
														// with the key
			e.setProperty(DEPARTMENT_ID_PROPERTY, dio.getDepartmentId()); // Set
																			// all
																			// properties
			e.setProperty(SUBJECT_TITLE_PROPERTY, dio.getSubjectTitle());
			e.setProperty(FACULTY_PROPERTY, dio.getFaculty());
			datastore.put(e); // put the entity in the datastore
			txn.commit(); // commit
			return true;
		}
		return false;
	}

	/**
	 * Checks the existence of a department in the datastore
	 * 
	 * @param dio
	 *            DepartmentInformationObject - department to be checked
	 * @return boolean value whether the department exists or not
	 */
	public boolean checkDepartmentExists(DepartmentInformationObject dio) {
		PreparedQuery pq = queryDepartment(dio);
		if (pq.countEntities(FetchOptions.Builder.withDefaults()) == 0)
			return false;
		return true;

	}

	/**
	 * Attempts to add a course entity to the datastore, will fail if duplicate
	 * was found in datastore
	 * 
	 * @param cio
	 *            CourseInformationObject - course data to be added
	 * @return boolean value whether add was successful or not
	 */
	public boolean addCourse(CourseInformationObject cio) {
		if (!checkCourseExists(cio)) {
			Transaction txn = datastore.beginTransaction();
			Key k = makeParentKey(cio);
			Entity e = new Entity(COURSE_KIND, k);
			e.setProperty(DEPARTMENT_ID_PROPERTY, cio.getDepartmentId());
			e.setProperty(COURSE_ID_PROPERTY, cio.getCourseId());
			e.setProperty(COURSE_TITLE_PROPERTY, cio.getCourseTitle());
			e.setProperty(PREREQ_PROPERTY, cio.getPrereqString());
			e.setProperty(COREQ_PROPERTY, cio.getCoreqString());
			e.setProperty(CREDIT_PROPERTY, cio.getCredits());
			datastore.put(e);
			txn.commit();
			return true;
		}
		return false;
	}

	/**
	 * Checks the existence of a course in the datastore
	 * 
	 * @param cio
	 *            CourseInformationObject - course to be checked
	 * @return boolean value whether the course exists or not
	 */
	public boolean checkCourseExists(CourseInformationObject cio) {
		PreparedQuery pq = queryCourse(cio);
		if (pq.countEntities(FetchOptions.Builder.withDefaults()) == 0)
			return false;
		return true;

	}

	/**
	 * Attempts to add a section entity to the datastore, will fail if duplicate
	 * was found in datastore
	 * 
	 * @param sio
	 *            SectionInformationObject - section data to be added
	 * @return boolean value whether add was successful or not
	 */
	public boolean addSection(SectionInformationObject sio) {
		if (!checkSectionExists(sio)) {
			Key k = makeParentKey(sio);
			Transaction txn = datastore.beginTransaction();
			Entity e = new Entity(SECTION_KIND, k);
			e.setProperty(DEPARTMENT_ID_PROPERTY, sio.getDepartmentId());
			e.setProperty(COURSE_ID_PROPERTY, sio.getCourseId());
			e.setProperty(SECTION_ID_PROPERTY, sio.getSectionId());
			e.setProperty(ACTIVITY_PROPERTY, sio.getActivity());
			e.setProperty(TERM_PROPERTY, sio.getTerm());
			e.setProperty(DAY_PROPERTY, sio.getDay());
			e.setProperty(LOCATION_PROPERTY, sio.getLocation());
			e.setProperty(START_PROPERTY, sio.getStart());
			e.setProperty(END_PROPERTY, sio.getEnd());
			e.setProperty(INSTRUCTOR_PROPERTY, sio.getInstructor());
			e.setProperty(BUILDING_PROPERTY, sio.getBuilding());
			e.setProperty(ROOM_PROPERTY, sio.getRoom());
			e.setProperty(CDF_PROPERTY, sio.isCdf());
			e.setProperty(DROP_NO_W_PROPERTY, sio.getDropNoWDate());
			e.setProperty(DROP_W_PROPERTY, sio.getDropWDate());
			datastore.put(e);
			txn.commit();
			System.out.println("Added section: " + sio.getSectionId());
			return true;
		}
		return false;
	}

	/**
	 * Checks the existence of a course in the datastore
	 * 
	 * @param sio
	 *            SectionInformationObject - section to be checked
	 * @return
	 */
	public boolean checkSectionExists(SectionInformationObject sio) {
		PreparedQuery pq = querySection(sio);
		if (pq.countEntities(FetchOptions.Builder.withDefaults()) == 0)
			return false;
		return true;
	}

	public boolean addBooks(BookInformationObject bio) {
		if (!checkBookExists(bio)) {
			Key k = makeParentKey(bio);
			Transaction txn = datastore.beginTransaction();
			Entity e = new Entity(BOOK_KIND, k);
			e.setProperty(DEPARTMENT_ID_PROPERTY, bio.getDepartmentId());
			e.setProperty(COURSE_ID_PROPERTY, bio.getCourseId());
			e.setProperty(SECTION_ID_PROPERTY, bio.getSectionId());
			e.setProperty(BOOK_TITLE_PROPERTY, bio.getTitle());
			e.setProperty(BOOK_REQUIRED_PROPERTY, bio.getRequired());
			e.setProperty(BOOK_AUTHOR_PROPERTY, bio.getAuthor());
			e.setProperty(BOOK_ISBN_PROPERTY, bio.getIsbn());
			datastore.put(e);
			txn.commit();
			return true;
		}
		return false;
	}

	public boolean checkBookExists(BookInformationObject bio) {
		PreparedQuery pq = queryBook(bio);
		if (pq.countEntities(FetchOptions.Builder.withDefaults()) == 0)
			return false;
		return true;
	}


	// helper query methods

	private PreparedQuery queryDepartment(DepartmentInformationObject dio) {
		Query q = new Query(DEPARTMENT_KIND);
		Key k = KeyFactory.createKey(DATASTORE_ENTITY_SET_NAME,
				DATASTORE_ENTITY_KEY_NAME);
		q.setAncestor(k);
		q.addFilter(DEPARTMENT_ID_PROPERTY, FilterOperator.EQUAL,
				dio.getDepartmentId());
		return datastore.prepare(q);
	}

	private PreparedQuery queryCourse(CourseInformationObject cio) {
		Query q = new Query(COURSE_KIND);
		q.addFilter(DEPARTMENT_ID_PROPERTY, FilterOperator.EQUAL,
				cio.getDepartmentId());
		q.addFilter(COURSE_ID_PROPERTY, FilterOperator.EQUAL, cio.getCourseId());
		return datastore.prepare(q);
	}

	private PreparedQuery querySection(SectionInformationObject sio) {
		Query q = new Query(SECTION_KIND);
		q.addFilter(DEPARTMENT_ID_PROPERTY, FilterOperator.EQUAL,
				sio.getDepartmentId());
		q.addFilter(COURSE_ID_PROPERTY, FilterOperator.EQUAL, sio.getCourseId());
		q.addFilter(SECTION_ID_PROPERTY, FilterOperator.EQUAL,
				sio.getSectionId());
		return datastore.prepare(q);
	}

	private PreparedQuery queryBook(BookInformationObject bio) {
		Query q = new Query(BOOK_KIND);
		q.addFilter(DEPARTMENT_ID_PROPERTY, FilterOperator.EQUAL,
				bio.getDepartmentId());
		q.addFilter(COURSE_ID_PROPERTY, FilterOperator.EQUAL, bio.getCourseId());
		q.addFilter(SECTION_ID_PROPERTY, FilterOperator.EQUAL,
				bio.getSectionId());
		q.addFilter(BOOK_ISBN_PROPERTY, FilterOperator.EQUAL, bio.getIsbn());
		return datastore.prepare(q);
	}

	public List<DepartmentInformationObject> getDepartmentList() {
		List<Entity> del = getKindEntityList(DEPARTMENT_KIND);
		List<DepartmentInformationObject> diol = new ArrayList<DepartmentInformationObject>();
		for (Iterator i = del.iterator(); i.hasNext();) {
			Entity e = (Entity) i.next();
			DepartmentInformationObject dio = getDepartmentFromEntity(e);
			diol.add(dio);
		}
		return diol;
	}

	public List<CourseInformationObject> getCourseList() {
		List<Entity> cel = getKindEntityList(COURSE_KIND);
		List<CourseInformationObject> ciol = new ArrayList<CourseInformationObject>();
		for (Iterator i = cel.iterator(); i.hasNext();) {
			Entity e = (Entity) i.next();
			CourseInformationObject cio = getCourseFromEntity(e);
			ciol.add(cio);
		}
		return ciol;
	}

	public List<CourseInformationObject> getCourseList(DepartmentInformationObject dio) {
		Query q = new Query(COURSE_KIND);
		q.addFilter(DEPARTMENT_ID_PROPERTY, FilterOperator.EQUAL, dio.getDepartmentId());
		q.addSort(DEPARTMENT_ID_PROPERTY, SortDirection.ASCENDING);
		q.addSort(COURSE_ID_PROPERTY, SortDirection.ASCENDING);
		List<Entity> cel = datastore.prepare(q).asList(FetchOptions.Builder.withDefaults());
		List<CourseInformationObject> ciol = new ArrayList<CourseInformationObject>();
		for (Iterator i = cel.iterator(); i.hasNext();) {
			Entity e = (Entity) i.next();
			CourseInformationObject cio = getCourseFromEntity(e);
			ciol.add(cio);
		}
		return ciol;
	}

	public List<SectionInformationObject> getSectionList() {
		List<Entity> sel = getKindEntityList(SECTION_KIND);
		List<SectionInformationObject> siol = new ArrayList<SectionInformationObject>();
		for (Iterator i = sel.iterator(); i.hasNext();) {
			Entity e = (Entity) i.next();
			SectionInformationObject sio = getSectionFromEntity(e);
			siol.add(sio);
		}
		return siol;
	}

	public List<SectionInformationObject> getSectionList(CourseInformationObject cio) {
		Query q = new Query(SECTION_KIND);
		q.addFilter(DEPARTMENT_ID_PROPERTY, FilterOperator.EQUAL, cio.getDepartmentId());
		q.addFilter(COURSE_ID_PROPERTY, FilterOperator.EQUAL, cio.getCourseId());
		q.addSort(DEPARTMENT_ID_PROPERTY, SortDirection.ASCENDING);
		q.addSort(COURSE_ID_PROPERTY, SortDirection.ASCENDING);
		q.addSort(SECTION_ID_PROPERTY, SortDirection.ASCENDING);		
		List<Entity> sel = datastore.prepare(q).asList(FetchOptions.Builder.withDefaults());
		List<SectionInformationObject> siol = new ArrayList<SectionInformationObject>();
		for (Iterator i = sel.iterator(); i.hasNext();) {
			Entity e = (Entity) i.next();
				SectionInformationObject sio = getSectionFromEntity(e);
				siol.add(sio);
		}
		return siol;
	}

	public List<BookInformationObject> getBookList(SectionInformationObject sio) {
		List<Entity> bel = getKindEntityList(BOOK_KIND);
		List<BookInformationObject> biol = new ArrayList<BookInformationObject>();
		for (Iterator i = bel.iterator(); i.hasNext();) {
			Entity e = (Entity) i.next();
			if (e.getProperty(DEPARTMENT_ID_PROPERTY).equals(
					sio.getDepartmentId())
					&& e.getProperty(COURSE_ID_PROPERTY).equals(
							sio.getCourseId())
					&& e.getProperty(SECTION_ID_PROPERTY).equals(
							sio.getCourseId())) {
				BookInformationObject bio = getBookFromEntity(e);
				biol.add(bio);
			}
		}
		return biol;
	}

	private List<Entity> getKindEntityList(String entityKind) {
		Query q = new Query(entityKind);
		if (entityKind.equals(DEPARTMENT_KIND)) {
			q.addSort(DEPARTMENT_ID_PROPERTY, SortDirection.ASCENDING);
		}
		else if (entityKind.equals(COURSE_KIND)) {
			q.addSort(DEPARTMENT_ID_PROPERTY, SortDirection.ASCENDING);
			q.addSort(COURSE_ID_PROPERTY, SortDirection.ASCENDING);
		} else if (entityKind.equals(SECTION_KIND)) {
			q.addSort(DEPARTMENT_ID_PROPERTY, SortDirection.ASCENDING);
			q.addSort(COURSE_ID_PROPERTY, SortDirection.ASCENDING);
			q.addSort(SECTION_ID_PROPERTY, SortDirection.ASCENDING);
		}
		List<Entity> results = datastore.prepare(q).asList(
				FetchOptions.Builder.withDefaults());
		return results;
	}

	private Key makeParentKey(CourseInformationObject cio) {
		Query q = new Query(DEPARTMENT_KIND);
		q.setKeysOnly();
		q.addFilter(DEPARTMENT_ID_PROPERTY, FilterOperator.EQUAL,
				cio.getDepartmentId());
		PreparedQuery pq = datastore.prepare(q);
		return pq.asSingleEntity().getKey();
	}

	private Key makeParentKey(SectionInformationObject sio) {
		Query q = new Query(COURSE_KIND);
		q.setKeysOnly();
		q.addFilter(DEPARTMENT_ID_PROPERTY, FilterOperator.EQUAL,
				sio.getDepartmentId());
		q.addFilter(COURSE_ID_PROPERTY, FilterOperator.EQUAL, sio.getCourseId());
		PreparedQuery pq = datastore.prepare(q);
		return pq.asSingleEntity().getKey();
	}

	private Key makeParentKey(BookInformationObject bio) {
		Query q = new Query(DEPARTMENT_KIND);
		q.setKeysOnly();
		q.addFilter(DEPARTMENT_ID_PROPERTY, FilterOperator.EQUAL,
				bio.getDepartmentId());
		q.addFilter(COURSE_ID_PROPERTY, FilterOperator.EQUAL, bio.getCourseId());
		q.addFilter(SECTION_ID_PROPERTY, FilterOperator.EQUAL,
				bio.getSectionId());
		PreparedQuery pq = datastore.prepare(q);
		return pq.asSingleEntity().getKey();
	}

	public DepartmentInformationObject queryDepartmentFromId(String departmentId) {
		Query q = new Query(DEPARTMENT_KIND);
		q.addFilter(DEPARTMENT_ID_PROPERTY, FilterOperator.EQUAL, departmentId);
		PreparedQuery pq = datastore.prepare(q);
		Entity e = pq.asSingleEntity();
		if (e == null)
			return null;
		return getDepartmentFromEntity(e);
	}

	public CourseInformationObject queryCourseFromId(String departmentId,
			String courseId) {
		Query q = new Query(COURSE_KIND);
		q.addFilter(DEPARTMENT_ID_PROPERTY, FilterOperator.EQUAL, departmentId);
		q.addFilter(COURSE_ID_PROPERTY, FilterOperator.EQUAL, courseId);
		PreparedQuery pq = datastore.prepare(q);
		Entity e = pq.asSingleEntity();
		if (e == null)
			return null;
		return getCourseFromEntity(e);
	}

	public SectionInformationObject querySectionFromId(String departmentId,
			String courseId, String sectionId) {
		Query q = new Query(SECTION_KIND);
		q.addFilter(DEPARTMENT_ID_PROPERTY, FilterOperator.EQUAL, departmentId);
		q.addFilter(COURSE_ID_PROPERTY, FilterOperator.EQUAL, courseId);
		q.addFilter(SECTION_ID_PROPERTY, FilterOperator.EQUAL, sectionId);
		PreparedQuery pq = datastore.prepare(q);
		Entity e = pq.asSingleEntity();
		if (e == null)
			return null;
		return getSectionFromEntity(e);
	}

	private DepartmentInformationObject getDepartmentFromEntity(Entity e) {
		String subjectTitle = (String) e.getProperty(SUBJECT_TITLE_PROPERTY);
		String subjectCode = (String) e.getProperty(DEPARTMENT_ID_PROPERTY);
		String faculty = (String) e.getProperty(FACULTY_PROPERTY);
		return new DepartmentInformationObject(subjectTitle, subjectCode,
				faculty);
	}

	private CourseInformationObject getCourseFromEntity(Entity e) {
		String departmentId = (String) e.getProperty(DEPARTMENT_ID_PROPERTY);
		String courseId = (String) e.getProperty(COURSE_ID_PROPERTY);
		String courseTitle = (String) e.getProperty(COURSE_TITLE_PROPERTY);
		String prereq = (String) e.getProperty(PREREQ_PROPERTY);
		String coreq = (String) e.getProperty(COREQ_PROPERTY);
		long credits = (Long) e.getProperty(CREDIT_PROPERTY);
		return new CourseInformationObject(departmentId, courseId, courseTitle,
				prereq, coreq, credits);
	}

	private SectionInformationObject getSectionFromEntity(Entity e) {
		String departmentId = (String) e.getProperty(DEPARTMENT_ID_PROPERTY);
		String courseId = (String) e.getProperty(COURSE_ID_PROPERTY);
		String sectionId = (String) e.getProperty(SECTION_ID_PROPERTY);
		String activity = (String) e.getProperty(ACTIVITY_PROPERTY);
		String term = (String) e.getProperty(TERM_PROPERTY);
		String day = (String) e.getProperty(DAY_PROPERTY);
		String location = (String) e.getProperty(LOCATION_PROPERTY);
		String start = (String) e.getProperty(START_PROPERTY);
		String end = (String) e.getProperty(END_PROPERTY);
		String instructor = (String) e.getProperty(INSTRUCTOR_PROPERTY);
		String building = (String) e.getProperty(BUILDING_PROPERTY);
		String room = (String) e.getProperty(ROOM_PROPERTY);
		boolean cdf = (Boolean) e.getProperty(CDF_PROPERTY);
		String dropNoW = (String) e.getProperty(DROP_NO_W_PROPERTY);
		String dropW = (String) e.getProperty(DROP_W_PROPERTY);
		return new SectionInformationObject(departmentId, courseId, sectionId,
				activity, term, day, location, start, end, instructor,
				building, room, cdf, dropNoW, dropW);
	}

	private BookInformationObject getBookFromEntity(Entity e) {
		String departmentId = (String) e.getProperty(DEPARTMENT_ID_PROPERTY);
		String courseId = (String) e.getProperty(COURSE_ID_PROPERTY);
		String sectionId = (String) e.getProperty(SECTION_ID_PROPERTY);
		String title = (String) e.getProperty(BOOK_TITLE_PROPERTY);
		String required = (String) e.getProperty(BOOK_REQUIRED_PROPERTY);
		String author = (String) e.getProperty(BOOK_AUTHOR_PROPERTY);
		String isbn = (String) e.getProperty(BOOK_ISBN_PROPERTY);
		return new BookInformationObject(departmentId, courseId, sectionId,
				title, required, author, isbn);
	}

	public List<DepartmentInformationObject> queryDepartmentByPrefix(String prefix) {
		Query q = new Query(DEPARTMENT_KIND);
		q.addFilter(DEPARTMENT_ID_PROPERTY, FilterOperator.GREATER_THAN_OR_EQUAL, prefix);
		q.addSort(DEPARTMENT_ID_PROPERTY,SortDirection.ASCENDING);
		PreparedQuery pq = datastore.prepare(q);
		List<Entity> results = pq.asList(FetchOptions.Builder.withLimit(10));
		List<DepartmentInformationObject> diol = new ArrayList<DepartmentInformationObject>();
		for(Iterator<Entity> i = results.iterator(); i.hasNext();) {
			Entity e = i.next();
			String deptId = (String)e.getProperty(DEPARTMENT_ID_PROPERTY);
			if(deptId.startsWith(prefix))
				diol.add(getDepartmentFromEntity(e));
		}
		return diol;
	}

	public List<CourseInformationObject> queryCourseByPrefix(String deptId, String prefix) {
		Query q = new Query(COURSE_KIND);
		q.addFilter(DEPARTMENT_ID_PROPERTY, FilterOperator.EQUAL, deptId);
		q.addFilter(COURSE_ID_PROPERTY, FilterOperator.GREATER_THAN_OR_EQUAL, prefix);
		q.addSort(DEPARTMENT_ID_PROPERTY, SortDirection.ASCENDING);
		q.addSort(COURSE_ID_PROPERTY, SortDirection.ASCENDING);
		PreparedQuery pq = datastore.prepare(q);	
		List<Entity> results = pq.asList(FetchOptions.Builder.withLimit(10));
		List<CourseInformationObject> ciol = new ArrayList<CourseInformationObject>();
		for(Iterator<Entity> i = results.iterator(); i.hasNext();) {
			Entity e = i.next();
			String courseId = (String)e.getProperty(COURSE_ID_PROPERTY);
			if(courseId.startsWith(prefix))
				ciol.add(getCourseFromEntity(e));
		}
		return ciol;
	}

	public List<SectionInformationObject> querySectionByPrefix(String deptId, String courseId, String prefix) {
		Query q = new Query(SECTION_KIND);
		q.addFilter(DEPARTMENT_ID_PROPERTY, FilterOperator.EQUAL, deptId);
		q.addFilter(COURSE_ID_PROPERTY, FilterOperator.EQUAL, courseId);
		q.addFilter(SECTION_ID_PROPERTY, FilterOperator.GREATER_THAN_OR_EQUAL, prefix);
		q.addSort(DEPARTMENT_ID_PROPERTY, SortDirection.ASCENDING);
		q.addSort(COURSE_ID_PROPERTY, SortDirection.ASCENDING);
		q.addSort(SECTION_ID_PROPERTY, SortDirection.ASCENDING);
		PreparedQuery pq = datastore.prepare(q);
		List<Entity> results = pq.asList(FetchOptions.Builder.withLimit(10));
		List<SectionInformationObject> siol = new ArrayList<SectionInformationObject>();
		for(Iterator<Entity> i = results.iterator(); i.hasNext();){
			Entity e = i.next();
			String sectionId = (String)e.getProperty(SECTION_ID_PROPERTY);
			if(sectionId.startsWith(prefix))
				siol.add(getSectionFromEntity(e)); 
		}
		return siol;
	}

	// public CourseInformationObject queryCourseFromTitle(String query){
	// Query q= new Query(COURSE_KIND);
	// q.addFilter(COURSE_TITLE_PROPERTY, FilterOperator.GREATER_THAN_OR_EQUAL,
	// query);
	// PreparedQuery pq = datastore.prepare(q);
	// List<Entity> results = pq.asList(
	// FetchOptions.Builder.withDefaults());
	// return getCourseFromEntity(e);
	// }
	//

}
